#include "AudioChannel.h"

AudioChannel::AudioChannel(int stream_index, AVCodecContext *codecContext, AVRational time_bae)
        : BaseChannel(
        stream_index, codecContext, time_bae) {
// 音频三要素
//1 采样率 44100 48000
//2 位声/采样格式大小  16 bit  == 2字节
//3 声道数 2

//   缓冲区 怎么定义  out_buffers    out_buffer_size
//   初始化缓冲区
//音频压缩数据包AAC ，原始数据一般是32位的，44100，双通道  -》 一般手机 44100 16位  2 声道
// 原始数据 到 手机播放数据的过程  重采样

    out_channel = av_get_channel_layout_nb_channels(
            AV_CH_LAYOUT_STEREO); //STEREO 双声道类型 == 获取声道数2
    out_simple_size = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16); //  采样格式 16bit  == 2字节
    out_sample_rate = 44100;

    out_buffer_size = out_channel * out_simple_size * out_sample_rate;
    out_buffer = static_cast<uint8_t *>(malloc(out_buffer_size));

    //ffmpeg 音频重采样    音频重采样上下文

    swr_ctx = swr_alloc_set_opts(0,
//                             下面是疏忽缓解
                                 AV_CH_LAYOUT_STEREO,
                                 AV_SAMPLE_FMT_S16,
                                 out_sample_rate,
//                               下面是输入环节

                                 codecContext->channel_layout,
                                 codecContext->sample_fmt,
                                 codecContext->sample_rate, 0, 0
    );
    swr_init(swr_ctx);


}


void *task_audio_decode(void *args) {
    auto *video_channel = static_cast<AudioChannel *>(args);
    video_channel->audio_decode();
    return nullptr;//必须返回
}

void *task_audio_play(void *args) {
    auto *video_channel = static_cast<AudioChannel *>(args);
    video_channel->audio_play();
    return nullptr;//必须返回
}

void AudioChannel::start() {
    isPlay = 1;
    packes.setWork(1);
    frames.setWork(1);
    //第一个线程，取出队列的压缩包进行编码，再将编码后的数据 push 到队列中
    pthread_create(&pid_audio_decode, 0, task_audio_decode, this);
//第二个线程 从队列中取出原始包，进行播放
    pthread_create(&pid_audio_play, 0, task_audio_play, this);
}

void AudioChannel::audio_decode() {

    AVPacket *pkt = nullptr;
    while (isPlay) {

        if (isPlay && frames.size() > 100) {
            av_usleep(10 * 1000);
            continue;
        }

        int ret = packes.getQueueAndDel(pkt);
        if (!isPlay) {
            break;
        }
        if (!ret) {
            continue;
        }
        ret = avcodec_send_packet(avCodecContext, pkt);
        if (ret) {
            break;
        }
        AVFrame *avFrame = av_frame_alloc();
        ret = avcodec_receive_frame(avCodecContext, avFrame);
//      音频也有 I P B 帧的概念，所以获取原始包的时候 最好还是判断下
        if (ret == AVERROR(EAGAIN)) {
//          B帧参考前面成功，参考后面失败，可能P帧没出来，再拿一次就好了
            continue;
        } else if (ret != 0) {
            if (avFrame) {
                releaseAVFrame(&avFrame);
            }
            break;  //发生错误  直接停止
        }
        //PCM原始数据
        frames.insertToQueue(avFrame);

        av_packet_unref(pkt);
        releaseAVPacket(&pkt);
    }
    av_packet_unref(pkt);
    releaseAVPacket(&pkt);


}

int AudioChannel::getPCM() {
    int pcm_size = 0;
    AVFrame *frame = 0;
    while (isPlay) {
        int ret = frames.getQueueAndDel(frame);
        if (!isPlay) {
            break;
        }
        if (!ret) {
            continue;
        }

//       开始重采样
//        来源：10个48000   ---->  目标:44100  11个44100
// 获取单通道的样本数 (计算目标样本数： ？ 10个48000 --->  48000/44100因为除不尽  11个44100)
        int dst_nb_samples = av_rescale_rnd(
                swr_get_delay(swr_ctx, frame->sample_rate) + frame->nb_samples,
                out_sample_rate, frame->sample_rate,
                AV_ROUND_UP
        );

//      重采样工作

        int sample_per_channel = swr_convert(swr_ctx, &out_buffer, dst_nb_samples,
                                             (const uint8_t **) frame->data, frame->nb_samples);

        pcm_size = sample_per_channel * out_simple_size * out_channel;

        audio_time = frame->best_effort_timestamp * av_q2d(time_base);

        if (this->jniCallBackHelper) {
            jniCallBackHelper->onProgress(THREAD_CHILD, audio_time);
        }

        break;
    }

    av_frame_unref(frame);
    releaseAVFrame(&frame);

    return pcm_size;
}


void bqPlayCallback(SLAndroidSimpleBufferQueueItf pItf, void *context) {
    auto *audio_channel = static_cast<AudioChannel *>(context);
    int pcm_size = audio_channel->getPCM();
    (*pItf)->Enqueue(
            pItf,//传递自己，因为没有this
            audio_channel->out_buffer,//PCM数据
            pcm_size// PCM数据对应的大小
    );
}

void AudioChannel::audio_play() {
//  用于执行成功或者事变的返回值
    SLresult result;

//    创建引擎，并获取引擎接口

    result = slCreateEngine(&engineObject, 0, 0, 0, 0, 0);
    if (SL_RESULT_SUCCESS != result) {
        LOGE("创建引擎失败");
        return;
    }

//  初始化引擎
    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    if (SL_RESULT_SUCCESS != result) {
        LOGE("初始化引擎失败");
        return;
    }

//   获取引擎接口
    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineInterface);
    if (SL_RESULT_SUCCESS != result) {
        LOGE("获取引擎接口失败");
        return;
    }

    if (engineInterface) {
        LOGE("获取引擎接口成功");
    } else {
        LOGE("获取引擎接口失败");
    }

//   创建混音器
    result = (*engineInterface)->CreateOutputMix(engineInterface, &outputMixObject, 0, 0, 0);
    if (SL_RESULT_SUCCESS != result) {
        LOGE("初始化混音器 CreateOutputMix failed");
        return;
    }
    //  初始化混音器

    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    if (SL_RESULT_SUCCESS != result) {
        LOGE("初始化混音器失败");
        return;
    }


//    创建播放器

    SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 10};

    //pcm数据格式
//SL_DATAFORMAT_PCM：数据格式为pcm格式
//2：双声道
//SL_SAMPLINGRATE_44_1：采样率为44100
//SL_PCMSAMPLEFORMAT_FIXED_16：采样格式为16bit
//SL_PCMSAMPLEFORMAT_FIXED_16：数据大小为16bit
//SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT：左右声道（双声道）
//SL_BYTEORDER_LITTLEENDIAN：小端模式

    SLDataFormat_PCM formatPcm = {
            SL_DATAFORMAT_PCM, 2,
            SL_SAMPLINGRATE_44_1,
            SL_PCMSAMPLEFORMAT_FIXED_16,
            SL_PCMSAMPLEFORMAT_FIXED_16,
            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
            SL_BYTEORDER_LITTLEENDIAN
    };

    //{数据源 将上述配置信息放到这个数据源中}
    SLDataSource audioSrc = {&loc_bufq, &formatPcm};
    //3.2 配置音轨（输出）
    //设置混音器
    SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    SLDataSink audioSnk = {&loc_outmix, NULL}; //最终混音器的成功

    const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};
    const SLboolean req[1] = {SL_BOOLEAN_TRUE};

    result = (*engineInterface)->CreateAudioPlayer(
            engineInterface,  //引擎接口
            &bqPlayerObject,  //播放器
            &audioSrc,  // 音频配置信息
            &audioSnk,  // 混音器
            1,  //开放的参数个数
            ids, // 代表我们需要的buffere
            req  //代表我们上面的buffer 需要开放出去
    );
    if (SL_RESULT_SUCCESS != result) {
        LOGE("创建播放器 CreateAudioPlayer failed!");
        return;
    }
//   初始化播放器

    result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);

    if (SL_RESULT_SUCCESS != result) {
        LOGE("实例化播放器 CreateAudioPlayer failed!");
        return;
    }
    LOGE("创建播放器 CreateAudioPlayer success!");


//   获取播放器接口
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayInterface);
    if (SL_RESULT_SUCCESS != result) {
        LOGE("获取播放接口 GetInterface SL_IID_PLAY failed!");
        return;
    }
    LOGE("3、创建播放器 Success");
//   设置回调函数

    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
                                             &bqPlayerBufferQueue);
    if (result != SL_RESULT_SUCCESS) {
        LOGE("获取播放队列 GetInterface SL_IID_BUFFERQUEUE failed!");
        return;
    }
    (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayCallback, this);

    LOGE("4、设置播放回调函数 Success");


//   设置播放状态
    (*bqPlayInterface)->SetPlayState(bqPlayInterface, SL_PLAYSTATE_PLAYING);

    LOGE("5、设置播放器状态为播放状态 Success");

    bqPlayCallback(bqPlayerBufferQueue, this);

    LOGE("6、手动激活回调函数 Success");

}


AudioChannel::~AudioChannel() {
    if (swr_ctx) {
        swr_free(&swr_ctx);
    }
    DELETE(out_buffer)
};


void AudioChannel::stop() {

    pthread_join(pid_audio_decode, nullptr);
    pthread_join(pid_audio_play, nullptr);

    isPlay = false;
    packes.setWork(0);
    frames.setWork(0);

    if (bqPlayInterface) {
        (*bqPlayInterface)->SetPlayState(bqPlayInterface, SL_PLAYSTATE_STOPPED);
        bqPlayInterface = nullptr;
    }

    if (bqPlayerObject) {
        (*bqPlayerObject)->Destroy(bqPlayerObject);
        bqPlayerObject = nullptr;
        bqPlayerBufferQueue = nullptr;
    }
    if (outputMixObject) {
        (*outputMixObject)->Destroy(outputMixObject);
        outputMixObject = nullptr;
    }

    if (engineObject) {
        (*engineObject)->Destroy(engineObject);
        engineObject = nullptr;
    }
    packes.clear();
    frames.clear();
}
